package com.greate.community.service;

import com.greate.community.entity.DiscussPost;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 搜索相关
 */
@Service
@Slf4j
public class ElasticsearchService {

    @Autowired
    private ElasticsearchRestTemplate elasticsearchRestTemplate;

    @PostConstruct
    public void initEs() {
        // 初始化es服务器，如果无 discuss-post 索引，则创建索引
        if (!elasticsearchRestTemplate.indexOps(DiscussPost.class).exists()) {
            log.info("es have no discuss-post index, create it");
            elasticsearchRestTemplate.indexOps(DiscussPost.class).create();
            elasticsearchRestTemplate.indexOps(DiscussPost.class).putMapping();
        } else {
            log.info("es have discuss-post index, do nothing");
        }
    }

    /**
     * 将数据插入 Elasticsearch 服务器
     *
     * @param post
     */
    public void saveDiscussPost(DiscussPost post) {
        elasticsearchRestTemplate.save(post);
    }

    /**
     * 从 Elasticsearch 服务器上查找数据
     *
     * @param id
     * @return
     */
    public DiscussPost getDiscussPostById(int id) {
        return elasticsearchRestTemplate.get(String.valueOf(id), DiscussPost.class);
    }

    /**
     * 将数据从 Elasticsearch 服务器中删除
     *
     * @param id
     */
    public void deleteDiscussPost(int id) {
        elasticsearchRestTemplate.delete(String.valueOf(id), DiscussPost.class);
    }

    /**
     * 分页搜索
     *
     * @param keyword 搜索的关键词
     * @param current 当前页码（这里的 Page 是 Spring 提供的，而非我们自己实现的那个）
     * @param limit   每页显示多少条数据
     * @return
     */
    public Page<DiscussPost> searchDiscussPost(String keyword, int current, int limit) {
        Pageable pageable = PageRequest.of(current, limit);
        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(QueryBuilders.multiMatchQuery(keyword, "title", "content"))
                .withSorts(SortBuilders.fieldSort("type").order(SortOrder.DESC),
                        SortBuilders.fieldSort("score").order(SortOrder.DESC),
                        SortBuilders.fieldSort("createTime").order(SortOrder.DESC))
                .withPageable(PageRequest.of(current, limit))
                .withHighlightFields(
                        new HighlightBuilder.Field("title"),
                        new HighlightBuilder.Field("content"))
                .withHighlightBuilder(
                        new HighlightBuilder().preTags("<em>").postTags("</em>").numOfFragments(0))
                .build();

        SearchHits<DiscussPost> searchHits = elasticsearchRestTemplate.search(searchQuery, DiscussPost.class);

        //封装page对象
        List<DiscussPost> content = new ArrayList<>();
        for (SearchHit<DiscussPost> productSearchHit : searchHits) {
            //高亮的内容
            Map<String, List<String>> highlightFields = productSearchHit.getHighlightFields();
            //将高亮的内容填充到content中
            productSearchHit.getContent().setTitle(highlightFields.get("title") == null ? productSearchHit.getContent().getTitle() : highlightFields.get("title").get(0));
            productSearchHit.getContent().setContent(highlightFields.get("content") == null ? productSearchHit.getContent().getContent() : highlightFields.get("content").get(0));
            //放到实体类中
            content.add(productSearchHit.getContent());
        }

        return new PageImpl<>(content, pageable, searchHits.getTotalHits());
    }

}
